#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
AI虚拟主播系统 - 正式一键启动脚本 v2.0
✅ 完整启动流程管理
✅ HTTP服务器内置启动
✅ 端口自动检测和清理
✅ 浏览器智能打开
✅ 完善的错误处理
"""

import sys
import os
import time
import socket
import http.server
import socketserver
import threading
import subprocess
import webbrowser
from pathlib import Path
from typing import Optional

# 切换到项目根目录
PROJECT_ROOT = Path(__file__).parent.absolute()
os.chdir(PROJECT_ROOT)
sys.path.insert(0, str(PROJECT_ROOT))


class Colors:
    """终端颜色"""
    GREEN = '\033[92m'
    RED = '\033[91m'
    YELLOW = '\033[93m'
    BLUE = '\033[94m'
    CYAN = '\033[96m'
    END = '\033[0m'
    BOLD = '\033[1m'


def print_color(text: str, color: str = Colors.GREEN):
    """彩色打印"""
    print(f"{color}{text}{Colors.END}")


def print_header(text: str):
    """打印标题"""
    print("\n" + "=" * 70)
    print(f"{Colors.BOLD}{Colors.CYAN}{text:^70}{Colors.END}")
    print("=" * 70 + "\n")


def check_port_available(port: int) -> bool:
    """检查端口是否可用"""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        try:
            s.bind(('', port))
            return True
        except OSError:
            return False


def kill_port_process(port: int) -> bool:
    """终止占用端口的进程"""
    try:
        if sys.platform == 'win32':
            # 查找占用端口的进程
            result = subprocess.run(
                f'netstat -ano | findstr :{port}',
                shell=True,
                capture_output=True,
                text=True
            )
            
            if result.stdout:
                lines = result.stdout.strip().split('\n')
                pids = set()
                
                for line in lines:
                    parts = line.split()
                    if len(parts) >= 5 and 'LISTENING' in line:
                        pid = parts[-1]
                        if pid.isdigit():
                            pids.add(pid)
                
                if pids:
                    for pid in pids:
                        subprocess.run(
                            f'taskkill /F /PID {pid}',
                            shell=True,
                            capture_output=True
                        )
                        print_color(f"  ✓ 已终止占用端口 {port} 的进程 (PID: {pid})", Colors.YELLOW)
                    
                    time.sleep(2)  # 等待端口完全释放
                    return check_port_available(port)
        else:
            # Linux/Mac
            subprocess.run(
                f'lsof -ti:{port} | xargs kill -9',
                shell=True,
                capture_output=True
            )
            time.sleep(2)
            return check_port_available(port)
            
    except Exception as e:
        print_color(f"  ✗ 清理端口失败: {e}", Colors.RED)
        return False
    
    return False


def ensure_port_available(port: int, service_name: str, max_retries: int = 3) -> bool:
    """确保端口可用"""
    print(f"检查端口 {port} ({service_name})...")
    
    for attempt in range(max_retries):
        if check_port_available(port):
            print_color(f"  ✓ 端口 {port} 可用", Colors.GREEN)
            return True
        else:
            print_color(f"  ⚠️  端口 {port} 被占用 (尝试 {attempt + 1}/{max_retries})", Colors.YELLOW)
            
            if attempt < max_retries - 1:
                if kill_port_process(port):
                    print_color(f"  ✓ 端口 {port} 已清理", Colors.GREEN)
                    continue
                else:
                    print_color(f"  ⚠️  端口 {port} 清理失败，重试中...", Colors.YELLOW)
                    time.sleep(1)
            else:
                print_color(f"  ✗ 端口 {port} 无法释放", Colors.RED)
                return False
    
    return False


def start_http_server() -> Optional[threading.Thread]:
    """启动HTTP服务器（内置线程方式）"""
    print_header("[1/3] 启动 HTTP 服务器")
    
    # 检查并清理端口
    if not ensure_port_available(8000, "HTTP服务器"):
        print_color("✗ 端口 8000 无法使用，请手动清理后重试", Colors.RED)
        return None
    
    try:
        # 创建HTTP请求处理器
        class CORSRequestHandler(http.server.SimpleHTTPRequestHandler):
            def end_headers(self):
                self.send_header('Access-Control-Allow-Origin', '*')
                self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
                self.send_header('Access-Control-Allow-Headers', 'Content-Type')
                self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
                super().end_headers()
            
            def log_message(self, format, *args):
                # 静默日志
                pass
        
        # 创建TCP服务器
        httpd = socketserver.TCPServer(
            ("", 8000),
            CORSRequestHandler,
            bind_and_activate=False
        )
        httpd.allow_reuse_address = True
        httpd.server_bind()
        httpd.server_activate()
        
        print_color("  ✓ HTTP 服务器创建成功", Colors.GREEN)
        
        # 在后台线程运行
        server_thread = threading.Thread(
            target=httpd.serve_forever,
            daemon=True,
            name="HTTPServer"
        )
        server_thread.start()
        
        print_color("  ✓ HTTP 服务器线程已启动", Colors.GREEN)
        
        # 验证服务器是否真的在运行
        time.sleep(1)
        
        # 测试连接
        try:
            test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            test_socket.settimeout(2)
            test_socket.connect(('localhost', 8000))
            test_socket.close()
            
            print_color("  ✓ HTTP 服务器验证成功", Colors.GREEN)
            print_color(f"  ✓ 地址: http://localhost:8000", Colors.CYAN)
            
            return server_thread
            
        except Exception as e:
            print_color(f"  ✗ HTTP 服务器验证失败: {e}", Colors.RED)
            httpd.shutdown()
            return None
            
    except Exception as e:
        print_color(f"  ✗ HTTP 服务器启动失败: {e}", Colors.RED)
        import traceback
        traceback.print_exc()
        return None


def wait_for_port(port: int, timeout: int = 30) -> bool:
    """等待端口开放"""
    start_time = time.time()
    while time.time() - start_time < timeout:
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.settimeout(1)
                s.connect(('localhost', port))
                return True
        except (ConnectionRefusedError, OSError, socket.timeout):
            time.sleep(0.5)
    return False


def start_main_program() -> Optional[subprocess.Popen]:
    """启动主程序"""
    print_header("[2/3] 启动主程序")
    
    # 检查并清理WebSocket端口
    if not ensure_port_available(8765, "WebSocket服务器"):
        print_color("⚠️  端口 8765 被占用但将尝试继续", Colors.YELLOW)
    
    try:
        # 启动主程序
        main_script = PROJECT_ROOT / "main.py"
        
        process = subprocess.Popen(
            [sys.executable, str(main_script)],
            stdout=sys.stdout,
            stderr=sys.stderr,
            cwd=str(PROJECT_ROOT)
        )
        
        print_color(f"  ✓ 主程序已启动 (PID: {process.pid})", Colors.GREEN)
        
        # 等待WebSocket服务器启动
        print("  等待 WebSocket 服务器启动...", end="", flush=True)
        
        if wait_for_port(8765, timeout=25):
            print_color(" ✓", Colors.GREEN)
            print_color(f"  ✓ WebSocket 服务器已就绪 (ws://localhost:8765)", Colors.GREEN)
            return process
        else:
            print_color(" ⚠️", Colors.YELLOW)
            print_color("  ⚠️  WebSocket 启动较慢，但程序正在运行", Colors.YELLOW)
            return process
            
    except Exception as e:
        print_color(f"  ✗ 主程序启动失败: {e}", Colors.RED)
        import traceback
        traceback.print_exc()
        return None


def open_browser() -> bool:
    """打开浏览器"""
    print_header("[3/3] 打开 Live2D 页面")
    
    # 等待所有服务就绪
    print("  等待所有服务就绪...", end="", flush=True)
    time.sleep(3)
    print_color(" ✓", Colors.GREEN)
    
    # 最后验证
    if not wait_for_port(8765, timeout=5):
        print_color("  ⚠️  WebSocket 服务器未就绪，页面可能无法连接", Colors.YELLOW)
    
    url = "http://localhost:8000/web_live2d_cubism4.html"
    print(f"  正在打开: {url}")
    
    try:
        webbrowser.open(url)
        print_color("  ✓ Live2D 页面已在浏览器中打开", Colors.GREEN)
        print_color("  ℹ️  如果未自动打开，请手动访问上述地址", Colors.CYAN)
        return True
    except Exception as e:
        print_color(f"  ✗ 打开浏览器失败: {e}", Colors.RED)
        print_color(f"  请手动打开: {url}", Colors.YELLOW)
        return False


def print_startup_info():
    """打印启动信息"""
    print_header("✅ 系统启动完成")
    
    print(f"{Colors.CYAN}📌 服务地址:{Colors.END}")
    print(f"  • HTTP 服务器:      http://localhost:8000")
    print(f"  • WebSocket 服务器: ws://localhost:8765")
    print(f"  • Live2D 页面:      http://localhost:8000/web_live2d_cubism4.html")
    
    print(f"\n{Colors.CYAN}📖 使用说明:{Colors.END}")
    print("  1. Live2D 页面应该已在浏览器中打开")
    print("  2. 系统正在监听B站直播间弹幕")
    print("  3. 观众发送弹幕后，AI会自动回复并播放语音")
    print("  4. Live2D角色会随语音进行口型同步")
    
    print(f"\n{Colors.CYAN}💡 提示:{Colors.END}")
    print("  • 查看配置: config/config.yaml")
    print("  • 按 Ctrl+C 停止所有服务")
    
    print("\n" + "-" * 70 + "\n")


def main():
    """主函数"""
    print_header("🎤 AI虚拟主播系统 - 一键启动 v2.0")
    
    print(f"{Colors.CYAN}📁 工作目录: {PROJECT_ROOT}{Colors.END}\n")
    
    # 记录启动的服务
    http_thread = None
    main_process = None
    
    try:
        # 1. 启动 HTTP 服务器
        http_thread = start_http_server()
        if not http_thread:
            print_color("\n✗ HTTP 服务器启动失败，无法继续", Colors.RED)
            return 1
        
        # 2. 启动主程序
        main_process = start_main_program()
        if not main_process:
            print_color("\n✗ 主程序启动失败", Colors.RED)
            return 1
        
        # 3. 打开浏览器
        open_browser()
        
        # 4. 显示启动信息
        print_startup_info()
        
        # 5. 等待用户中断
        try:
            print_color("系统运行中，按 Ctrl+C 停止...\n", Colors.GREEN)
            while True:
                if main_process.poll() is not None:
                    print_color("\n⚠️  主程序已退出", Colors.YELLOW)
                    break
                time.sleep(1)
        except KeyboardInterrupt:
            print_color("\n\n收到停止信号...", Colors.YELLOW)
        
    except Exception as e:
        print_color(f"\n✗ 启动过程中出现错误: {e}", Colors.RED)
        import traceback
        traceback.print_exc()
        return 1
        
    finally:
        # 清理资源
        print_header("正在停止所有服务")
        
        if main_process:
            try:
                main_process.terminate()
                main_process.wait(timeout=5)
                print_color("✓ 主程序已停止", Colors.GREEN)
            except Exception as e:
                print_color(f"⚠️  停止主程序失败: {e}", Colors.YELLOW)
        
        # HTTP服务器会随线程自动结束（daemon=True）
        print_color("✓ HTTP 服务器已停止", Colors.GREEN)
        
        # 清理端口
        print("\n正在清理端口...")
        if not check_port_available(8000):
            kill_port_process(8000)
        if not check_port_available(8765):
            kill_port_process(8765)
        
        print_header("系统已安全关闭")
        print_color("感谢使用 AI虚拟主播系统！\n", Colors.CYAN)
    
    return 0


if __name__ == '__main__':
    try:
        exit_code = main()
        sys.exit(exit_code)
    except Exception as e:
        print_color(f"\n✗ 致命错误: {e}", Colors.RED)
        import traceback
        traceback.print_exc()
        sys.exit(1)
